package com.navinfo.tripanalysis.common.arithmetic;

import com.navinfo.tripanalysis.common.arithmetic.common.*;
import com.navinfo.tripanalysis.common.arithmetic.custom.VarSpeedOver;
import com.navinfo.tripanalysis.common.arithmetic.enums.EventStatus;
import com.navinfo.tripanalysis.common.arithmetic.annotation.Arithmetic;
import com.navinfo.tripanalysis.common.arithmetic.convert.EventDataConvert;
import com.navinfo.tripanalysis.common.arithmetic.exception.RangeAssert;
import com.navinfo.tripanalysis.common.arithmetic.manager.AbstractArithmetic;
import com.navinfo.tripanalysis.common.config.ConfigMap;
import com.navinfo.tripanalysis.common.protocol.java.EventDataPb;
import com.navinfo.tripanalysis.common.util.ArithmeticUtils;

import java.util.Optional;

/**
 * 超速算法<br>
 * 依赖{@link Mileage}里程油耗算法<br/>
 * 输出：统计、事件<br/>
 */
@Arithmetic(name = "超速算法")
public class SpeedOver extends AbstractArithmetic<VarSpeedOver> {
    /**
     * 事件类型
     */
    private static final EventDataPb.EventType eventType = EventDataPb.EventType.vehicleOverSpeed;
    /**
     * 超速阀值90KM/H
     */
    private double overSpeedThreshold = ConfigMap.getInteger("V_Spd_Threshold_90");
    /**
     * 超速90KM/H时长阀值
     */
    private long overSpeedTimeThresholdMs = ConfigMap.getLong("OverSpeed_Time_90");

    /**
     * 是否超速，速度超过90KM/H并且持续30秒算超速
     */
    private boolean isOverSpeed() {
        return getCommonData().getSpeedKmh() >= overSpeedThreshold;
    }

    @Override
    public void calculate() {
        logger.debug("进入超速算法.");
        VarSpeedOver var = getObj();
        CommonData commonData = getCommonData();

        //1.速度有效性判断
        RangeAssert.speedKmhIsInTheRange(commonData.getSpeedKmh());

        //2.上一次和本次的超速状态
        boolean preIsOverSpeed = var.isPreOverSpeed();
        boolean curIsOverSpeed = isOverSpeed();
        logger.debug("超速算法，超速状态：pre:{},current:{}", preIsOverSpeed, curIsOverSpeed);

        //3、算法计算
        switch (getEventStatus(preIsOverSpeed, curIsOverSpeed)) {
            case START:
                logger.debug("超速算法，事件开始.");
                startEventData(eventType);
                break;
            case IN:
                logger.debug("超速算法，事件中.");
                calcEventData(eventType);
                break;
            case END:
                logger.debug("超速算法，事件结束.");
                calcEventData(eventType);
                endEvent();
                break;
            default:
                logger.debug("超速算法：上一次和本次都未超速，跳出算法.[terminalId:{}]", terminalId);
        }


        //4.最后一个点，判断是否有持续30秒的事件，开始事件的肯定就抛弃了，事件中的需要判断一下
        if (commonData.isTripLastNode()) {
            endEvent();
        }

        var.setPreOverSpeed(curIsOverSpeed);
        logger.debug("超速算法结束.");
    }

    @Override
    public void collect(OuterStatisticData statisticDataOut) {
        VarSpeedOver varSpeedOver = super.getObj();
        statisticDataOut.setSo90Number(varSpeedOver.getNumber());
        statisticDataOut.setSo90Mileage(ArithmeticUtils.mileageMToM(varSpeedOver.getMileage()));
        statisticDataOut.setSo90Fuel(ArithmeticUtils.fuelMlToMl(varSpeedOver.getFuel()));
        statisticDataOut.setSo90Duration(ArithmeticUtils.timeMsToSecond(varSpeedOver.getDuration()));
    }


    /**
     * 处理事件的结束状态
     */
    private void endEvent() {
        Optional.ofNullable(drivingData.getEventData(eventType)).ifPresent(eventData -> {
            EventDataConvert.convertEnd(eventData, drivingData);
            if (Optional.ofNullable(eventData.getDuration()).orElse(0L) >= overSpeedTimeThresholdMs) {
                //事件结束，将事件数据赋值到统计数据中
                eventDataToVar(eventData);
                //放入输出事件列表
                drivingData.addEventDataToList(eventData);
            }

            drivingData.removeEventData(eventType);
        });
    }

    /**
     * 事件数据赋值到统计数据中
     * @param eventData
     */
    private void eventDataToVar(OuterEventData eventData){
        VarSpeedOver varSpeedOver = super.getObj();
        //事件结束，统计里程、油耗、时长、次数加1
        varSpeedOver.addMileage(Optional.ofNullable(eventData.getExtendField05()).orElse(0.0));
        varSpeedOver.addFuel( Optional.ofNullable(eventData.getExtendField06()).orElse(0.0));
        varSpeedOver.addDuration( Optional.ofNullable(eventData.getDuration()).orElse(0L).intValue());
        varSpeedOver.setNumber(varSpeedOver.getNumber() + 1);
    }
}
